<?php

namespace app\service;

use app\exception\ModelEmptyException;
use app\exception\ModelException;
use app\model\Attachment;
use app\model\Category;
use app\model\CategorySubContent;
use app\model\InnerChart;
use app\model\InnerChartSubContent;
use app\model\Model;
use app\model\Module;
use app\model\ModuleField;
use app\model\RecycleBin;
use app\model\SubContent;
use app\model\Tag;
use app\model\Website;
use app\scaffold\Table;
use Overtrue\Pinyin\Pinyin;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Db;

class ContentService {

    /**
     * @var \app\model\Content
     */
    public static $model = null;
    /**
     * @var array
     */
    public static $macro = [];

    public static $hasOne = [];

    public static $belongsTo = [];

    public static $hasMany = [];

    protected static $arrayField =  ['多图','多视频','多文件','日期时间区间','列表多选','多选'];

    /**
     * @var \app\scaffold\Table
     */
    protected $table;

    public function __construct()
    {
        $this->table = new Table();
    }

    public static function getTagHotContent($param)
    {

    }

    /**
     * @throws ModelException
     * @throws ModelEmptyException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\db\exception\DbException
     */
    public static function tagTagContentList()
    {
        if(empty($param['limit'])){
            $param['limit'] = null;
        }
        $tids = explode(',',$param['cid']);
        if(!count($tids)){
            return [];
        }

        $module = self::getModule($param['module_id'],$param['sellerId']);
        $table = $module['table'];
        $attachField = self::getAttachField($module['moduleField']);
        self::setModel($table);
        $cateSub = new CategorySubContent();
        if(count($tids) == 1){
            $where = [
                'tag_id' => $tids[0],
                'seller_id' => $param['sellerId'],
                'website_id' => $param['websiteId']
            ];
        }else{
            $where = [
                ['category_id','in',$tids],
                ['seller_id','=',$param['sellerId']],
                ['website_id','=', $param['websiteId']]
            ];
        }
        $cateSubCon = $cateSub->where($where)->select()->toArray();
        return self::tagContent($cateSubCon, $param, $attachField);
    }

    /**
     * @throws ModelEmptyException
     * @throws \think\db\exception\DataNotFoundException
     * @throws ModelException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\db\exception\DbException
     */
    public static function getTagRecommend($param)
    {
        $cid = (int)input('cid');
        if(empty($param['cid'])){
            if($cid){
                $cateIds = [$cid];
            }else{
                return [];
            }
        }else{
            $cateIds = explode(',',$param['cid']);
        }
        $Category = new Category();
        if(count($cateIds) == 1){
            $cate = $Category->getCategory(['id'=>$cateIds[0],'seller_id'=>$param['sellerId'],'website_id'=>$param['siteId'],'lang'=>$param['lang']])['data']->toArray();
            $parentPath = $cate['path'] . $cate['id'] . '-';
            $cates = $Category->getCategoryList([['path','like',$parentPath . '%'],['seller_id','=',$param['sellerId']],['website_id','=' ,$param['siteId']],['lang','=',$param['lang']]])['data']->toArray();
            array_push($cates,$cate);
            $cateIds= array_column($cates,'id');
        }else{
            $cates = $Category->getCategoryList([['id','in',$cateIds],['website_id','=' ,$param['siteId']]])['data']->toArray();
            $cateIdArr= array_column($cates,'id');
            $cateIds = array_intersect($cateIds,$cateIdArr);
        }
        $module = self::getModule($param['module_id'],$param['sellerId']);
        $table = $module['table'];
        $attachField = self::getAttachField($module['moduleField']);
        self::setModel($table);
        $cateSub = new CategorySubContent();
        $subId = (int)input('id');
        $where = [
            ['category_id','in',$cateIds],
            ['seller_id','=',$param['sellerId']],
        ];
        if($subId && $cid){
            $where[] = ['sub_content_id','<>',$subId];
        }
        $cateSubCon = $cateSub->where($where)->select()->toArray();
        if(!empty($cateSubCon)){
            $cateSubConLen =  count($cateSubCon);
            if( $cateSubConLen < $param['limit']){
                $param['limit'] = $cateSubConLen;
            }
            $cateSubConKey = array_rand($cateSubCon,$param['limit']);
            $tmp = [];
            if(!empty($cateSubConKey)){
                foreach ($cateSubConKey as $val){
                    array_push($tmp,$cateSubCon[$val]);
                }
                $cateSubCon = $tmp;
            }
        }
        return self::tagContent($cateSubCon, $param, $attachField);
    }

    /**
     * @throws ModelException
     * @throws ModelEmptyException
     */
    public static function getTagContentDetail($id, $sellerId, $lang, $siteId)
    {
        try {
            $SubContent = new SubContent();
            $where = [
                ['id','=',$id],
                ['seller_id','=',$sellerId],
                ['publish_time','<',date('Y-m-d H:i:s',time())],
                ['status','=',1],
                ['is_del','=',1],
            ];
            $dbPrefix = env('database.prefix');
            $subContent = $SubContent->getSubContent($where,['category.module.moduleField'=>function($q)use($lang,$siteId,$sellerId,$dbPrefix){
                $q->where([ $dbPrefix . 'category.seller_id'=>$sellerId, $dbPrefix . 'category.website_id'=>$siteId,'lang'=>$lang]);
            },'thumbnail'=>function($q){
                $q->field('id,name,url,type');
            },'cover'=>function($q){
                $q->field('id,name,url,type');
            }])['data']->toArray();
            $cate = $subContent['category'];
            $article = '';
            if(!empty($cate)){
                $table = $cate['0']['module']['table'];
                self::setModel($table);
                $article = self::$model->where(['sub_id' => $id, 'seller_id' => $sellerId])->find();
                $attachField = self::setSpecialField($cate[0]['module']['moduleField']);
                self::getSpecialField($article,$attachField);
            }
            $subContent['main_content'] = $article;
        }catch (ModelEmptyException $me){
            throw new ModelEmptyException($me->getMessage());
        } catch (\Exception $e){
            throw new ModelException($e->getMessage());
        }
        return $subContent;
    }

    /**
     * 分页标签数据
     * @throws ModelException
     */
    public static function tagContentPage($param)
    {
        if(!empty($param['cid'])){
            $cid = $param['cid'];
        }else{
            $cid = (int)request()->param('id');
        }
        $Category = new Category();
        $cate = $Category->getCategory(['id'=>$cid,'seller_id'=>$param['sellerId'],'lang'=>$param['lang']],['module.moduleField'])['data']->toArray();
        if($cate['parent_map'] && empty($param['cid'])){
            $cate = $Category->getCategory(['id'=>$cate['parent_map'],'seller_id'=>$param['sellerId'],'lang'=>$param['lang']],['module.moduleField'])['data']->toArray();
        }
        $path = $cate['path'] . $cid . '-';
        $cates = $Category->getCategoryList([['website_id','=',$param['siteId']],['lang','=',$param['lang']],['path','like',$path.'%']])['data']->toArray();
        if(empty($param['limit'])){
            $param['limit'] = null;
        }
        $cateIds = array_column($cates,'id');
        array_push($cateIds,$cid);
        if(!count($cateIds)){
            return [];
        }
        $table = $cate['module']['table'];
        self::setModel($table);
        $attachField = self::getAttachField($cate['module']['moduleField']);
        $cateSub = new CategorySubContent();
        if(count($cateIds) == 1){
            $where = [
                'category_id' => $cateIds[0],
                'seller_id' => $param['sellerId'],
            ];
        }else{
            $where = [
                ['category_id','in',$cateIds],
                ['seller_id','=',$param['sellerId']],
            ];
        }

        $cateSubCon = $cateSub->where($where)->select()->toArray();
        return self::tagContent($cateSubCon, $param, $attachField);
    }

    /**
     * 内容标签数据
     * @throws ModelEmptyException
     * @throws ModelException
     */
    public static function tagContentList($param)
    {
        $module = self::getModule($param['module_id'],$param['sellerId']);
        $table = $module['table'];
        self::setModel($table);
        if(empty($param['limit'])){
            $param['limit'] = null;
        }
        $cateIds = explode(',',$param['cid']);
        if(!count($cateIds)){
            return [];
        }
        $Category = new Category();

        if($param['all'] == 1){
            $cid = $cateIds[0];
            $cate = $Category->getCategory([['id','=',$cid],['website_id','=' ,$param['siteId']]])['data'];
            $path = $cate['path'] . $cid . '-';
            $subCate = $Category->getCategoryList([['path','like',$path . '%'],['website_id','=' ,$param['siteId']]])['data']->toArray();
            $cateIds = array_column($subCate,'id');
            array_push($cateIds,$cid);
        }else{
            $cates = $Category->getCategoryList([['id','in',$cateIds],['website_id','=' ,$param['siteId']]])['data']->toArray();
            $cateIdArr= array_column($cates,'id');
            $cateIds = array_intersect($cateIds,$cateIdArr);
        }
        $attachField = self::getAttachField($module['moduleField']);

        $cateSub = new CategorySubContent();
        if(count($cateIds) == 1){
            $where = [
                'category_id' => $cateIds[0],
                'seller_id' => $param['sellerId'],
            ];
        }else{
            $where = [
                ['category_id','in',$cateIds],
                ['seller_id','=',$param['sellerId']],
            ];
        }
        $cateSubCon = $cateSub->where($where)->select()->toArray();
        return self::tagContent($cateSubCon, $param, $attachField);
    }

    /**
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\db\exception\DbException
     */
    public static function tagContent($cateSubCon, $param, $attachField)
    {
        $SubContent = new SubContent();
        if(empty($cateSubCon)){
            if($param['asPage'] == 1 && $param['onlyData']==1){
                return  ['count' => 0, 'data' => []];
            }else if($param['asPage'] == 1 && $param['onlyData'] == 2 ){
                return  $SubContent->where(['id'=>0])->paginate(10);
            }else{
                return  [];
            }
        }else{
            $where = self::setPageWhere($param);
            $subIds = array_column($cateSubCon,'sub_content_id');
            $mainField = explode(',',$param['mainField']);
            array_push($mainField,'seller_id');
            if(!empty($param['subField'])){
                $subField  = explode(',',$param['subField']);
            }else{
                $subField  = $param['subField'];
            }

            $content = $SubContent->field($mainField);

            $with = [];
            if(in_array('thumbnail',$mainField) || $mainField == '*'){
                $with = self::setMainImageWith('thumbnail',$with);
            }
            if(in_array('cover',$mainField) || $mainField == '*'){
                $with = self::setMainImageWith('cover',$with);
            }
            if(!empty($with)){
                $content = $SubContent->field($mainField)->with($with);
            }
            $order = self::setOrder($param['sort']);

            $content = $content -> where($where)->whereIn('id',$subIds)->whereTime('publish_time','<=',time())->order($order);
            if($param['asPage'] == 1){
                $page = request()->param('page');
                if($page){
                    $param['page'] = $page;
                }
                $limit = request()->param('limit');
                if($limit){
                    $param['limit'] = $limit;
                }
                $query = request()->except(['id','cid','page','limit']);
                if(!empty($query)){
                    $content->where($query);
                }
                $content = $content->paginate([
                    'page' => $param['page'],
                    'list_rows' => $param['limit'],
                ]);
            }else{
                if(!empty($param['limit'])){
                    $content->limit((int)$param['limit']);
                }
                $content = $content->select();
            }
            $cateSubCon = getColumnForKeyArray($cateSubCon,'sub_content_id');
            $content->each(function(&$item)use($param,$attachField,$subField,$cateSubCon,$with){
                $item['category_id'] = $cateSubCon[$item['id']]['category_id'];
                if(!empty($subField)){
                    $mainContent = self::$model->where(['sub_id'=>$item['id'],'seller_id'=>$param['sellerId']])->find();
                    $mainContent = self::getMainContent($mainContent,$attachField);
                    $item['main_content'] = $mainContent;
                }
                if(isset($with['thumbnail'])){
                    $item['thumbnail'] = $item->toArray()['thumbnail'];
                }
                if(isset($with['cover'])){
                    $item['cover'] = $item->toArray()['cover'];
                }
                $item['tag'] = Db::name('tag_sub_content')->alias('a')
                    ->join('tag b', 'b.id = a.tag_id')
                    ->where('a.sub_content_id', '=', $item['id'])
                    ->where('b.is_del',1)
                    ->field('b.*')->select();
            });
            if($param['asPage'] == 1){
                if($param['onlyData'] == 1){
                    return ['total'=>$content->total(),'data'=>$content->all()];
                }else{
                    return $content;
                }
            }else{
                return $content->toArray();
            }
        }
    }

    // 主表附件关联设置
    public static function setMainImageWith($imgKey,$default = ['tag']): array
    {
        $tmpWith =  [
            $imgKey => function($q){
                $q->field('id,name,url,type');
            }
        ];
        return array_merge($default,$tmpWith);
    }

    // 查询条件
    public static function setPageWhere($param): array
    {
        $where = [
            'seller_id'=>$param['sellerId'],
            'status' => 1,
            'is_del'=>1,
        ];
        if($param['isTop'] != 2){
            $where['is_top'] = 1;
        }
        if($param['isCommend'] != 2){
            $where['is_recommend'] = 1;
        }
        return $where;
    }

    // 排序规则
    public static function setOrder($sort):string
    {
        $defaultOrder = "is_top asc,top_time desc";
        if($sort == 'publish_time desc'){
           $sort = $defaultOrder .',' . $sort;
        }else{
            $sort = $sort . ',' . $defaultOrder;
        }
        return  $sort;
    }

    /**
     *  置顶
     * @throws ModelException
     */
    public function topOpt($param): \think\response\Json
    {
        $SubContent = new SubContent();
        $where = [
            'id' => $param['id'],
            'seller_id' => $param['seller_id']
        ];
        if($param['is_top'] == 1){
            $top_time = time();
        }else{
            $top_time = 0;
        }
        $data = [
            'is_top' => $param['is_top'],
            'top_time' => $top_time
        ];
         $res = $SubContent->updateSubContent($where,$data);
         return json($res);
    }

    /**
     * 推荐
     * @throws ModelException
     */
    public function recommendAndStatus($param): \think\response\Json
    {
        $SubContent = new SubContent();
        $where = [
            'id' => $param['id'],
            'seller_id' => $param['seller_id']
        ];
        if($param['type'] == 'recommend'){
            $data = [
                'is_recommend' => $param['is_recommend']
            ];
        }else{
            $data = [
                'status' => $param['status']
            ];
        }
        $res = $SubContent->updateSubContent($where,$data);
        return json($res);
    }

    /**
     * 副表内容
     * @throws ModelException
     * @throws ModelEmptyException
     * @throws \think\db\exception\DbException
     */
    public function mainContent($param): \think\response\Json
    {
        $moduleModel = new Module();
        $module = $moduleModel->getModule(['id'=>$param['module_id'],'seller_id'=> $param['seller_id']],['moduleField'])['data']->toArray();
        $table = $module['table'];
        self::setModel($table);
        $Category = new Category();
        $cateWhere = [
            'seller_id' => $param['seller_id'],
            'module_id' => $param['module_id'],
            'website_id' => $param['website_id'],
        ];
        $cateIds= $Category->getColumn($cateWhere)['data'];
        $subCate = new CategorySubContent();
        $field = [];
        foreach($module['moduleField'] as $val){
            if(!empty($val['settings']['relation']) && $val['settings']['relation'] == 'belongs_to_many'){
                continue;
            }else{
                array_push($field,$val['table_field']);
            }
        }
        array_unshift($field,'id');
        $subIds =  $subCate->whereIn('category_id',$cateIds)->column('sub_content_id');

        $mainContent = self::$model->field($field)->whereIn('sub_id',$subIds)->paginate($param['limit'])->each(function($item)use($module){
            $attachField = $this->setSpecialField($module['moduleField']);
            self::getSpecialField($item,$attachField);
        });
        return json(['code' => 0, 'msg' => 'ok', 'count' => $mainContent->total(), 'data' => $mainContent->all()]);
    }

    /**
     * 内容新增
     * @throws \app\exception\ModelEmptyException
     * @throws \app\exception\ModelException
     */
    public function createContent($param): \think\response\Json
    {
        $sortField = $this->getContentField($param);
        return jsonReturn(0,'success',$sortField);
    }

    /**
     * 内容新增保存
     * @throws \app\exception\ModelEmptyException
     * @throws \app\exception\ModelException
     */
    public function saveContent($param): array
    {
        $moduleModel = new Module();
        $module = $moduleModel->getModule(['id'=>$param['module_id'],'seller_id'=> $param['admin']['seller_id']],['moduleField','category'])['data']->toArray();
        $table = $module['table'];
        $cateFlag = $this->verifiedCate($module,$param['category_id']);
        if($cateFlag['code'] != 0){
            return $cateFlag;
        }
        self::setModel($table);
        // 主表添加记录
        // 生成字段规则验证
        $mainData = $this->setMainContentData($module['id'],$param);
        Db::startTrans();
        try {
            // 主表记录添加结束
            $content = self::$model->create($mainData);
            $mainId = $content -> id;

            if(!empty(self::$macro)){
                foreach (self::$macro as $macro){
                    if(!empty($mainData[uncamelize($macro)])){
                        $mainData[uncamelize($macro)] = json_decode($mainData[uncamelize($macro)],true);
                        if(is_string($mainData[uncamelize($macro)])){
                            $tmpData = explode(',',$mainData[uncamelize($macro)]);
                        }else{
                            $tmpData = $mainData[uncamelize($macro)];
                        }
                        $content->$macro()->attach($tmpData);
                    }
                }
            }
            // 附表添加记录
            $subContent = new SubContent();
            $subData = $this->getSubData($param,$mainId);
            $subData['module_id'] = $param['module_id'];
            if(empty($subData['seo_title'])){
                $subData['seo_title'] = $subData['title'];
            }
            if(empty($subData['seo_keyword'])){
                $subData['seo_keyword'] = $subData['title'];
            }
            if(empty($subData['seo_description'])){
                $subData['seo_description'] = $this->descExtraction($subData['content']);
            }
            $subRes = $subContent->create($subData);
            $sub_id = $subRes->id;
            // 内链数据
            $inner = Cache::get(md5(strip_tags($param['sub_content']['content'])));
            if(!empty($inner)){
                foreach ($inner as &$val){
                    $val['sub_content_id'] = $sub_id;
                    $val['seller_id'] = $subRes['seller_id'];
                }
                unset($val);
                $innerModel = new InnerChartSubContent();
                $innerModel->saveAll($inner);
            }
            // 关联分类
            $subRes->category()->attach($cateFlag['data'],['seller_id'=>$param['admin']['seller_id']]);
            // 关联标签
            if(!empty($subData['tag'])){
                $tag = $this->dealWithContentTag($subData['tag'],$param['category_id'],$param['admin']['seller_id']);
                $subRes->tag()->attach($tag,['seller_id'=>$param['admin']['seller_id']]);
            }
            // 主表更新记录，添加附表主键
            $content->sub_id = $sub_id;
            $content->save();
            // 操作日志
            optEventLog($sub_id,'栏目内容','添加');
            Db::commit();
        }catch(\Exception $e){
            Db::rollback();
            return dataReturn(50012,$e->getMessage());
        }
        return dataReturn(0,'保存成功',$subRes);
    }

    /**
     * 内容列表
     * @param $param
     * @return \think\response\Json
     * @throws ModelException
     * @throws \think\db\exception\DbException
     * @throws ModelEmptyException
     */
    public function indexContent($param): \think\response\Json
    {
        $Cate = new Category();
        $cate = $Cate->getCategoryList(['seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang']])['data']->toArray();
        if(empty($cate)){
            return json(['code' => 0, 'msg' => 'ok', 'count' => 0, 'data' => []]);
        }
        $cateIds = array_column($cate,'id');
        $cateSub = new CategorySubContent();
        if(empty($param['category_ids'])){
            $cateSubWhere = [
                ['seller_id','=',$param['seller_id']],
                ['category_id','in',$cateIds]
            ];
        }else{
            $param['category_ids'] = array_intersect($param['category_ids'],$cateIds);
            $cateSubWhere = [
                ['seller_id','=',$param['seller_id']],
                ['category_id','in',$param['category_ids']]
            ];
        }
        $cateSubCon = $cateSub->getAllCategorySubContent($cateSubWhere)['data'];
        if(empty($cateSubCon)){
            return json(['code' => 0, 'msg' => 'ok', 'count' => 0, 'data' => []]);
        }else{
            $subIds = array_column($cateSubCon,'sub_content_id');
            $SubContent = new SubContent();
            $content = $SubContent->with(['thumbnail'=>function($q){
                $q->field('id,name,url,type');
            },'category'])->where(['seller_id'=>$param['seller_id'],'is_del'=>1]);
            if(!empty($param['title'])){
                $content = $content -> whereLike('title','%' . $param['title'] . '%');
            }
            $data = $content ->whereIn('id',$subIds)
                ->order('id','desc')
                ->paginate($param['limit'])->each(function (&$item)use($param){
                    if(!empty($item['category'])){
                        $Website = new Website();
                        $website = $Website -> getWebsite(['id'=>$param['website_id'],'seller_id'=>$param['seller_id']])['data'];
                        $item['url'] = 'http://' . $website['domain'] . $item['category'][0]['alias'] . '/' . $item['id'];
                    }
                });
            return json(['code' => 0, 'msg' => 'ok', 'count' => $data->total(), 'data' => $data->all()]);
        }
    }

    // 上一篇
    public static function getPreContent($param)
    {
        $cateCacheKey = 'hc_detail_cate_' .$param['seller_id'] .'_'.$param['website_id'].'_'. $param['lang'].'_'.$param['cid'];
        $cate = cache($cateCacheKey);
        $table = $cate['module']['table'];
        self::setModel($table);
        try {
            $SubContent = new SubContent();
            $cateSub = new CategorySubContent();
            $cateSubCon = $cateSub->getAllCategorySubContent(['category_id'=>$cate['id']])['data'];
            $subIds = array_column($cateSubCon,'sub_content_id');

            $where = [
                ['id','<',$param['id']],
                ['id','in',$subIds],
                ['seller_id','=',$param['seller_id']],
                ['status','=',1],
                ['is_del','=',1],
            ];
            $subContent = $SubContent->with(['thumbnail'=>function($q){
                $q->field('id,name,url,type');
            },'cover'=>function($q){
                $q->field('id,name,url,type');
            }])->where($where)->whereTime('publish_time','<',time())->order('id desc')->find();
        }catch (ModelEmptyException $me){
            throw new ModelEmptyException();
        } catch (\Exception $e){
            throw new ModelException();
        }
        return $subContent;
    }

    // 下一篇
    public static function getNextContent($param)
    {
        $cateCacheKey = 'hc_detail_cate_' .$param['seller_id'] .'_'.$param['website_id'].'_'. $param['lang'].'_'.$param['cid'];
        $cate = cache($cateCacheKey);
        $table = $cate['module']['table'];
        self::setModel($table);
        try {
            $SubContent = new SubContent();
            $cateSub = new CategorySubContent();
            $cateSubCon = $cateSub->getAllCategorySubContent(['category_id'=>$cate['id']])['data'];
            $subIds = array_column($cateSubCon,'sub_content_id');
            $where = [
                ['id','>',$param['id']],
                ['id','in',$subIds],
                ['seller_id','=',$param['seller_id']],
                ['status','=',1],
                ['is_del','=',1],
            ];
            $subContent = $SubContent->with(['thumbnail'=>function($q){
                $q->field('id,name,url,type');
            },'cover'=>function($q){
                $q->field('id,name,url,type');
            }])->where($where)->whereTime('publish_time','<',time())->order('id asc')->find();
        }catch (ModelEmptyException $me){
            throw new ModelEmptyException();
        } catch (\Exception $e){
            throw new ModelException();
        }
        return $subContent;
    }

    /**
     * 前台详情
     * @param $param
     * @return mixed
     * @throws ModelEmptyException
     * @throws ModelException
     */
    public function getContentDetail($param)
    {
        $cate = $param['cate'];
        $table = $cate['module']['table'];
        self::setModel($table);
        try {
            $SubContent = new SubContent();
            $where = [
                ['id','=',$param['id']],
                ['seller_id','=',$param['seller_id']],
                ['publish_time','<',date('Y-m-d H:i:s',time())],
                ['status','=',1],
                ['is_del','=',1],
            ];
            $subContent = $SubContent->getSubContent($where,['thumbnail'=>function($q){
                $q->field('id,name,url,type');
            },'cover'=>function($q){
                $q->field('id,name,url,type');
            },'tag'=>function($query)use($param){
                $query->where(['website_id'=>$param['website_id'],'lang'=>$param['lang']]);
            }])['data'];
            $article = self::$model->where(['sub_id' => $param['id'], 'seller_id' => $param['seller_id']])->find();
            if(empty($article)){
                throw new ModelEmptyException();
            }
            $attachField = $this->setSpecialField($cate['module']['moduleField']);

            $this->getSpecialField($article,$attachField);
            $subContent['main_content'] = $article;



        }catch (ModelEmptyException $me){
            throw new ModelEmptyException();
        } catch (\Exception $e){
            throw new ModelException();
        }
        return $subContent;
    }

    /**
     * 内容详情
     * @throws \app\exception\ModelEmptyException
     * @throws ModelException
     */
    public function readContent($param): \think\response\Json
    {
        $moduleModel = new Module();
        $module = $moduleModel->getModule(['id'=>$param['module_id'],'seller_id'=> $param['seller_id']],['moduleField'])['data']->toArray();
        $table = $module['table'];
        self::setModel($table);
        try {
            $SubContent = new SubContent();
            $subContent = $SubContent->getSubContent(['id'=>$param['id'],'seller_id'=>$param['seller_id'],'is_del'=>1],['thumbnail'=>function($q){
                $q->field('id,name,url,type');
            },'cover'=>function($q){
                $q->field('id,name,url,type');
            },'category','tag'=>function($query)use($param){
                $query->where(['website_id'=>$param['website_id'],'lang'=>$param['lang']]);
            }])['data']->toArray();
            $article = self::$model->where(['sub_id' => $param['id'], 'seller_id' => $param['seller_id']])->find();

             if(empty($article)){
                throw new ModelEmptyException();
            }

             $cate = $subContent['category'];
            if(!empty($cate)){
                $cateIds = array_column($cate,'id');
                $subContent['category'] = $cateIds;
                $siteIds = array_values(array_unique(array_column($cate,'website_id')));
                $subContent['website'] = $siteIds;
            }
             $tag = $subContent['tag'];
             if(!empty($tag)){
                 $tagIds = implode(',',array_column($tag,'title'));
                 $subContent['tag'] = $tagIds;
             }else{
                 $subContent['tag'] = '';
             }
             $attachField = $this->setSpecialField($module['moduleField']);
             $this->getSpecialField($article,$attachField);

             $subContent['main_content'] = $article;
         }catch (ModelEmptyException $me){
             throw new ModelEmptyException();
         } catch (\Exception $e){
             throw new ModelException();
         }
        $contentField = $this->getModuleField($param);
        return jsonReturn(0,'success',[
            'field' => $contentField,
            'content' => $subContent
        ]);
    }

    /**
     * 获取附件字段
     * @param $moduleField
     * @return array[]
     */
    public static function getAttachField($moduleField): array
    {
        return self::setSpecialField($moduleField);
    }

    /**
     * @param $article
     * @param $attachField
     * @return mixed
     */
    public static function getMainContent($article, $attachField)
    {
        self::getSpecialField($article,$attachField);
        return $article;
    }

    public static function getSpecialField(&$article,$attachField)
    {
        self::getAttachPath($article,$attachField);
        if(!empty(self::$hasOne)){
            foreach(self::$hasOne as $hasOne){
                $article[$hasOne['local_key']] = self::getHasOneData($hasOne['table'],$hasOne['foreign_key'],$article[$hasOne['local_key']],$article['seller_id']);
            }
        }

        if(!empty(self::$belongsTo)){
            foreach(self::$belongsTo as $belong){
                $article[$belong['local_key']] = self::getHasOneData($belong['table'],$belong['foreign_key'],$article[$belong['local_key']],$article['seller_id']);
            }
        }
        if(!empty(self::$hasMany)){
            foreach(self::$hasMany as $hasMany){
                $article[$hasMany['local_key']] = self::getHasManyData($hasMany['table'],$hasMany['foreign_key'],$article[$hasMany['local_key']],$article['seller_id']);
            }
        }

        if(!empty(self::$macro)){
            foreach(self::$macro as $macro){
                $article[uncamelize($macro)] = $article->$macro()->select()->toArray();
            }
        }
    }

    /**
     * 内容删除
     * @param $param
     * @return \think\response\Json
     */
    public function deleteContent($param): \think\response\Json
    {
        $module = $this->getModule($param['module_id'], $param['seller_id']);
        $table = $module['table'];
        self::setModel($table);
        Db::startTrans();
        try{
            $SubContent = new SubContent();
            $subContent = $SubContent->where(['id'=>$param['id'],'seller_id'=>$param['seller_id'],'is_del'=>1])->find();
            if(empty($subContent)){
                return jsonReturn(0,'删除成功',$subContent);
            }
            // 主表软删
            $subContent->is_del = 2;
            $subContent->delete_time = time();
            $subContent->update_time = time();
            $subContent->save();
            // 副表软删
            $content = self::$model->where(['sub_id'=>$param['id'],'seller_id'=>$param['seller_id']])->find();
            if(!empty($content)){
                $content->is_del = 2;
                $content->delete_time = time();
                $content->update_time = time();
                $content->save();
            }

            // 复制删除内容到回收站表
            $recycleBin = new RecycleBin();
            $binData = [
                'seller_id' => $param['seller_id'],
                'object_id' => $content ? $content['id'] : 0,
                'sub_id' => $subContent['id'],
                'module_id' => $param['module_id'],
                'table_name' => $module['title'].'-'.$module['table'],
                'title' => !empty($subContent['title']) ? $subContent['title'] : $module['title'].'内容',
                'admin_id' => $param['admin_id'],
                'name' => $param['name'],
            ];
            $recycleBin -> addRecycleBin($binData);
            // 操作日志
            optEventLog($subContent['id'],'栏目内容','删除');
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            return jsonReturn(50025,$e->getMessage());
        }
        return jsonReturn(0,'删除成功',$content);
    }

    /**
     * 更新内容
     * @throws ModelException
     * @throws ModelEmptyException
     */
    public function updateContent(&$param): \think\response\Json
    {
        $module = $this->getModule($param['module_id'], $param['admin']['seller_id']);
        $table = $module['table'];
        self::setModel($table);
        $cateFlag = $this->verifiedCate($module,$param['category_id']);
        if($cateFlag['code'] != 0){
            return json($cateFlag);
        }
        $content = self::$model->with('subContent.category')->where(['sub_id'=>$param['id'],'seller_id'=>$param['admin']['seller_id']])->find();
        if(empty($content)){
            return jsonReturn(40004,'内容不存在');
        }
        $subContent = $content['subContent'];
        // 主表添加记录
        // 生成字段规则验证
        $param['main_id'] = $content['id'];
        $mainData = $this->setMainContentData($module['id'],$param,true);
        Db::startTrans();
        try {
            // 主表更新内容
            $res = $content->saveAll([$mainData]);
            $mainId = $content -> id;
            if(!empty(self::$macro)){
                foreach (self::$macro as $macro){
                    $content->$macro()->detach();
                    $mainData[uncamelize($macro)] = json_decode($mainData[uncamelize($macro)],true);
                    if(is_string($mainData[uncamelize($macro)])){
                        $tmpData = explode(',',$mainData[uncamelize($macro)]);
                    }else{
                        $tmpData = $mainData[uncamelize($macro)];
                    }
                    $content->$macro()->attach($tmpData);
                }
            }
            // 附表添加记录
            $param['sub_id'] = $content['subContent']['id'];
            $subData = $this->getSubData($param,$mainId,true);
            $subContent->saveAll([$subData]);
            $subContent->category()->detach();
            $subContent->category()->attach($cateFlag['data'],['seller_id'=>$param['admin']['seller_id']]);
            // 关联标签
            $tag = $this->dealWithContentTag($subData['tag'],$param['category_id'],$param['admin']['seller_id']);
            $subContent->tag()->detach();
            $subContent->tag()->attach($tag,['seller_id'=>$param['admin']['seller_id']]);
            // 操作日志
            optEventLog($param['sub_id'],'栏目内容','更新');
            Db::commit();
        }catch(\Exception $e){
            Db::rollback();
            return jsonReturn(50012,$e->getMessage());
        }
        return jsonReturn(0,'保存成功',$res);

    }

    /**
     * @throws \Exception
     */
    public function dealWithContentTag($tagParam, $cateParam, $sellerId = 1): array
    {
        // 关联标签
        if(is_string($tagParam)){
            $tag = explode(',',$tagParam);
        }else{
            $tag = $tagParam;
        }
        $Category = new Category();
        $category = $Category -> getAllCustomData([['id','in',$cateParam]])['data'];
        $lang = array_column($category,'lang')[0];
        $siteId = array_unique(array_column($category,'website_id'));
        $Tag = new Tag();
        $tagList = $Tag -> getAllCustomData([['seller_id','=',$sellerId],['website_id','in',$siteId],['title','in',$tag]])['data'];
        $tagUniqueFlag = array_column($tagList,'unique_tag');
        $tagList = getColumnForKeyArray($tagList,'unique_tag');
        $tagIds = [];
        $pinyin = new Pinyin();
            $diffData = [];
            foreach ($tag as $val) {
                $tmp = [
                    'seller_id' => $sellerId,
                    'website_id' => '',
                    'lang' => $lang,
                    'title' => $val,
                    'first_letter' => substr(strtoupper($pinyin->abbr($val,PINYIN_KEEP_ENGLISH)),0,1),
                    'seo_title' => $val,
                    'seo_keywords' => $val,
                    'seo_description' => $val
                ];
                foreach ($siteId as $vv){
                    $tmp['website_id'] = $vv;
                    $tmpUnique = $tmp['seller_id'] . '-' . $vv . '-' . $lang .'-'.$tmp['title'];
                    if(!in_array($tmpUnique,$tagUniqueFlag)){
                        $tmp['unique_tag'] = $tmpUnique;
                        array_push($diffData, $tmp);
                    }else{
                        array_push($tagIds,$tagList[$tmpUnique]['id']);
                    }
                }
            }
           $tag =  $Tag->saveAll($diffData);

            $tmpIds = [];
            foreach ($tag as $item){
                array_push($tmpIds,(int)$item->id);
            }
        return array_merge($tagIds,$tmpIds);
    }

    /**
     * 设置主表内容
     * @param $moduleId
     * @param $param
     * @param false $isEdit
     * @return mixed|\think\response\Json
     * @throws ModelException
     * @throws \Exception
     */
    public function setMainContentData($moduleId, $param, bool $isEdit = false)
    {
        $moduleField = new ModuleField();
        $field = $moduleField->getModuleFieldList(['module_id'=>$moduleId,'seller_id'=>$param['admin']['seller_id']])['data']->toArray();
        $rule = [];
        $arrayFieldKey=[];
        foreach ($field as $val){
            if(!empty($val['validate_rule'])){
                $rule_key = $val['table_field'] .'|'. $val['form_title'];
                $rule[$rule_key] = $val['validate_rule'];
            }
            if(in_array($val['type'],self::$arrayField)){
                $rule_key = $val['table_field'] .'|'. $val['form_title'];
                $rule[$rule_key] = 'array';
                array_push($arrayFieldKey,$val['table_field']);
            }
            if($val['type'] == '关联字段' && $val['settings']['relation'] == 'belongs_to_many'){
                $middle = $val['settings']['local_table'] . '_' . $val['settings']['table'];
                $func = camelize($val['table_field']);
                $foreign_key = $val['settings']['table'] . '_' . $val['settings']['foreign_key'];
                $local_key = $val['settings']['local_table'] . '_' . $val['settings']['local_key'];
                $this->setRelation($func,$val['settings']['table'],$middle,$foreign_key,$local_key);
            }
            if($val['type'] == '关联字段' && ($val['settings']['relation'] == 'has_many' || $val['settings']['relation'] == 'belongs_to_many')){
                array_push($arrayFieldKey,$val['table_field']);
            }
        }

        // 验证数据
        if(!empty($rule)){
            try{
                validate($rule)->check($param['main_content']);
            }catch (ValidateException $e){
                throw new \Exception($e->getError(),-422);
            }
        }
        $mainData = $param['main_content'];
        foreach($mainData as $mainKey => $main){
            if(in_array($mainKey,$arrayFieldKey) && !empty($main)){
                $mainData[$mainKey] = json_encode($main);
            }
        }
        
        $mainData['seller_id'] = $param['admin']['seller_id'];
        if($isEdit){
            $mainData['id'] = $param['main_id'];
        }
        return $mainData;
    }

    /**
     * 验证分类
     * @param $module
     * @param $categoryIds
     * @return array
     */
    public function verifiedCate($module,$categoryIds): array
    {
        if(empty($module['category'])){
            $cateIds = [];
        }else{
            $cateIds = array_column($module['category'],'id');
            $cateFlag = array_diff($categoryIds,$cateIds);
        }
        if(empty($cateIds) || !empty($cateFlag)){
            return dataReturn(50029,'有栏目数据不属于该模型，请重新选择');
        }
        return dataReturn(0,'success',$categoryIds);
    }

    /**
     * 获取特殊字段（附件+关联关系字段+数组格式转换字段）
     * @param $param
     * @return array
     */
    public static function setSpecialField($param): array
    {
        // 单附件
        $singleField = [];
        // 多附件
        $multiField = [];
        // 格式转化字段
        $arrField = [];

        foreach($param as $item){
            if(in_array($item['form_type'],['image','video','file'])){
                array_push($singleField,$item['table_field']);
            }
            if(in_array($item['form_type'],['multiImage','multiVideo','multiFile'])){
                array_push($multiField,$item['table_field']);
            }
            if($item['form_type'] == 'reference'){
                if($item['settings']['relation'] == 'has_one'){
                    $func = camelize($item['table_field']);
                    $tmp = [
                        // 关联方法
                        'func_name' => $func,
                        'table' => $item['settings']['table'],
                        'local_key' => $item['settings']['local_key'],
                        'foreign_key' => $item['settings']['foreign_key'],
                    ];
                    self::$hasOne[$item['table_field']] = $tmp;
                }

                if($item['settings']['relation'] == 'belongs_to'){
                    $func = camelize($item['table_field']);
                    $tmp = [
                        // 关联方法
                        'func_name' => $func,
                        'table' => $item['settings']['table'],
                        'local_key' => $item['settings']['local_key'],
                        'foreign_key' => $item['settings']['foreign_key'],
                    ];
                    self::$belongsTo[$item['table_field']] = $tmp;
                }

                if($item['settings']['relation'] == 'has_many'){
                    $tmp = [
                        // 关联方法
                        'func_name' => camelize($item['table_field']),
                        'table' => $item['settings']['table'],
                        'local_key' => $item['settings']['local_key'],
                        'foreign_key' => $item['settings']['foreign_key'],
                    ];
                    self::$hasMany[$item['table_field']] = $tmp;
                }
                if($item['settings']['relation'] == 'belongs_to_many'){

                    $middle = $item['settings']['local_table'] . '_' . $item['settings']['table'];
                    $foreign_key = $item['settings']['table'] . '_' . $item['settings']['foreign_key'];
                    $local_key = $item['settings']['local_table'] . '_' . $item['settings']['local_key'];
                    self::setRelation(camelize($item['table_field']),$item['settings']['table'],$middle,$foreign_key,$local_key);
                }
            }
            if(in_array($item['form_type'],['dateTimeRange','multiSelect','checkbox'])){
                array_push($arrField,$item['table_field']);
            }
        }
        return [
            'single' => $singleField,
            'multi' => $multiField,
            'arrField' => $arrField,
        ];
    }

    /**
     * 获取附件链接
     */
    public static function getAttachPath($item, $attachField)
    {
        $attachment = new Attachment();
        // 单附件
        if(count($attachField['single'])){
            $singleIds = [];
            $singleField = [];
            foreach($attachField['single'] as $val){
//                if($item[$val]){
                    array_push($singleIds,$item[$val]);
                    $singleField[$val] = $item[$val];
//                }
            }
            $singleAttach = $attachment->field('id,name,url,type')->whereIn('id',$singleIds)->select()->toArray();
            $singleAttach = getColumnForKeyArray($singleAttach,'id');
            if(!empty($singleAttach)){
                foreach ($singleField as $kk => $vv){
                    if($vv == 0 || !isset($singleAttach[$vv])){
                        $item[$kk] = null;
                    }else{
                        $item[$kk] = $singleAttach[$vv];
                    }
                }
            }

        }

        // 多附件
        if(count($attachField['multi'])){
            $idStr = [];
            $multiFields = [];
            foreach($attachField['multi'] as $multi){
                if($item[$multi]){
                    $idArr = json_decode($item[$multi],true);
                    $multiFields[$multi] = $idArr;
                    $idStr = array_merge($idStr,$idArr);
                }else{
                    $item[$multi] = [];
                }
            }
            if(!empty($idStr)){
                $multiIds = array_unique($idStr);
                $multiAttach = $attachment -> field('id,name,url,type')->whereIn('id',$multiIds)->select()->toArray();

                $multiAttach = getColumnForKeyArray($multiAttach,'id');
                foreach($multiFields as $km => $vm){
                    $attachments = [];
                    if(!empty($multiAttach)){
                        foreach ($vm as $vvm) {
                            if(isset($multiAttach[intval($vvm)])){
                                array_push($attachments,$multiAttach[intval($vvm)]);
                            }
                        }
                    }
                    $item[$km] = $attachments;
                }
            }
        }
        // 数组转化字段
        if(count($attachField['arrField'])){
            foreach($attachField['arrField'] as $ak => $ar){
                if(!empty($ar)){
                    if(empty($item[$ar])){
                        $item[$ar] = [];
                    }else{
                        $item[$ar] = json_decode($item[$ar],true);
                    }
                }
            }
        }
    }

    /**
     * 获取一对一关联数据
     * @param $relationTable
     * @param $key
     * @param $val
     * @param string $field
     * @param int $sellerId
     * @return mixed
     */
    public static function getHasOneData($relationTable, $key, $val, int $sellerId,string $field = '*')
    {
        $model = self::getRelationModel($relationTable);
        $res = $model->field($field)->where($key,$val)->where('seller_id',$sellerId)->find();
        if(!empty($res)){
            $res = $res->toArray();
        }
        return $res;
    }

    /**
     * 获取多对多关联数据
     * @param $relationTable
     * @param $key
     * @param $val
     * @param string $field
     * @param int $sellerId
     * @return mixed
     */
    public static function getHasManyData($relationTable, $key, $val, int $sellerId,string $field = '*')
    {
        $model = self::getRelationModel($relationTable);
        $tmpData = [];
        if($val){
            $tmpData = json_decode($val,true);
        }
        return $model->field($field)->whereIn($key,$tmpData)->where('seller_id',$sellerId)->select()->toArray();
    }

    /**
     * @throws ModelEmptyException
     * @throws ModelException
     */
    public static function getRelationModel($relationTable)
    {
        $modelName = '\\app\\model\\' . ucfirst(camelize($relationTable));
        $module = new Module();
        $tableFlag = $module->getCustomData(['table'=>$relationTable])['data'];
        if(!empty($tableFlag)){
            $modelName = '\\app\\model\\customModel\\' . ucfirst(camelize($relationTable));
        }
        return new $modelName();
    }

    /**
     * 设置模型关联关系
     * @param Model $model
     * @param array $assocField
     */
    public static function setRelation($func,$table,$middle,$foreign_key,$local_key)
    {
        $modelName = '\\app\\model\\' . ucfirst(camelize($table));
        $module = new Module();
        $tableFlag = $module->getCustomData(['table'=>$table])['data'];
        if(!empty($tableFlag)){
            $modelName = '\\app\\model\\customModel\\' . ucfirst(camelize($table));
        }
        array_push(self::$macro,$func);
        $closure = function ()use($modelName,$middle,$foreign_key,$local_key){
            return $this->belongsToMany($modelName,$middle,$foreign_key,$local_key);
        };
        self::$model->macro($func,$closure);
    }

    /**
     * 获取字段值和注释
     *
     * @param string $table
     * @return array
     */
    public function getTableField(string $table): array
    {
        return $this->table->getTableField($table);
    }

    /**
     * @throws ModelEmptyException
     * @throws ModelException
     */
    public function getModuleField($param)
    {
        $module = self::getModule($param['module_id'],$param['seller_id']);
        return $module['moduleField'];
    }

    /**
     * 获取内容展示字段
     * @throws ModelException
     * @throws \app\exception\ModelEmptyException
     */
    public function getContentField($param): array
    {
        $module = self::getModule($param['module_id'],$param['seller_id']);
        $sort_field = [];
        $field = $this->getTableField($module['database_table']);
        // 自定义模型
        // 处理数组顺序,按照数据表字段排序，确定表单顺序
        $form_field = $module['moduleField'];
        foreach($form_field as $val){
            foreach($field as $k => $v){
                if(isset($v['column_name'])){
                    if($val['table_field'] == $v['column_name']){
                        $sort_field[$k] = $val;
                    }
                }else{
                    if($val['table_field'] == $v['COLUMN_NAME']){
                        $sort_field[$k] = $val;
                    }
                }
            }
        }

        ksort($sort_field);

        return $sort_field;
    }

    /**
     * @throws ModelEmptyException
     * @throws ModelException
     */
    public  static function getModule($module_id,$seller_id)
    {
        $moduleModel = new Module();
        return $moduleModel->getModule(['id'=>$module_id,'seller_id'=> $seller_id],['moduleField','category'])['data']->toArray();
    }

    /**
     * 获取分类
     * @throws \app\exception\ModelEmptyException
     * @throws ModelException
     */
    public static function getCate($param)
    {
        $category = new Category();
        return $category->getCategory($param,['module.moduleField'])['data']->toArray();
    }

    /**
     * 设置模型
     * @param string $table
     */
    public static function setModel(string $table)
    {
        $class = '\\app\\model\\' . ucfirst(camelize($table));
        $module = new Module();
        $tableFlag = $module->getCustomData(['table'=>$table])['data'];
        if(!empty($tableFlag)){
            $class = '\\app\\model\\customModel\\' . ucfirst(camelize($table));
        }
        return self::$model = new $class();
    }

    /**
     * 组装附表数据
     * @param $param
     * @param $mainId
     * @return mixed
     */
    public function getSubData($param, $mainId, $isEdit = false)
    {
        $subData = $param['sub_content'];
        $subData['main_id'] = $mainId;
        $subData['seller_id'] = $param['admin']['seller_id'];
        $subData['admin_id'] = $param['admin']['uid'];
        if(empty($subData['author'])){
            $subData['author'] = $param['admin']['name'];
        }
        if($isEdit){
            $subData['id'] = $param['sub_id'];
        }
        if(empty($subData['tag'])){
            $subData['tag'] = '';
        }
        return $subData;
    }

    /**
     * 图片本地化
     * @param $content
     * @return array|string|string[]
     */
    public function imgExtraction($content,$sellerId,$website = '')
    {
        $filePath = date('Ymd');
        $imgPath = CMS_ROOT . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'image' . DIRECTORY_SEPARATOR .$filePath ;
        $content = $this->cleanContent($content);
        $imgArr = getPatternMatchImages($content);
        $img_search = [];
        $img_replace = [];
        $attachmentData = [];
        if(!empty($imgArr)){
            foreach ($imgArr as $imgUrl){
                // 相同图片直接掠过
                if(in_array($imgUrl,$img_search)){
                    continue;
                }
                $img_search[] = $imgUrl;
                $ext=strrchr($imgUrl,".");
                ob_start();
                if(preg_match('/http/',$imgUrl)){
                    readfile($imgUrl);
                }else{
                    if(!preg_match('/^\/data/',$imgUrl)){
                        readfile($website . '/' .$imgUrl);
                    }
                }
                $img = ob_get_contents();
                ob_end_clean();
                $filename = md5(microtime(true).rand());
                $imgFile =  $imgPath . DIRECTORY_SEPARATOR . $filename .  $ext;
                if(!file_exists($imgPath)){
                    mkdir($imgPath);
                }
                $fp2=@fopen($imgFile, "a");
                fwrite($fp2,$img);
                fclose($fp2);
                $localPath = DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'image' . DIRECTORY_SEPARATOR .$filePath .DIRECTORY_SEPARATOR . $filename .  $ext;
                // 保存到附件
                $size = filesize($imgFile);
                $tmpAttach = [
                    'seller_id' => $sellerId,
                    'name' => $filename,
                    'size' => round($size / 1024,2),
                    'url'  => DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'image' . DIRECTORY_SEPARATOR .$filePath .DIRECTORY_SEPARATOR . $filename .  $ext,
                    'type' => 2,
                    'mime_type' => $ext,
                ];
                $attachmentData[] = $tmpAttach;
                $img_replace[] = $localPath;
            }
        }
        if(!empty($attachmentData)){
            $Attachment = new Attachment();
            $Attachment->addAllCustomData($attachmentData);
        }
        if(!empty($img_search) && !empty($img_replace)){
            $content = str_replace($img_search,$img_replace,$content);
        }
        return $content;
    }

    /**
     * 简介提取
     * @param $content
     * @param int $index
     * @return string
     */
    public function descExtraction($content, int $index = 0): string
    {
        if(empty($content)){
            return $content;
        }
        $content = $this->cleanContent($content);
        $content = htmlspecialchars_decode($content);
        $content = strip_tags($content);
        $content = str_replace(["\r","\n","\t","\r\n"],[''],$content);
        return trim(hcSubstr($content,100)) . '...';
    }

    /**
     * 文章导入
     * @param $param
     */
    public function articleUpload($param): array
    {
        if(empty($param['file'])){
            return dataReturn(0,'保存成功');
        }
        $file = $param['file'];
        // 提取标题和简介
        $title = $file -> getOriginalName();
        $title = str_replace('.txt','',$title);
        $keywords = $title;
        $tmpName = $file->getPathname();
        $text = file_get_contents($tmpName);
        $tmpContent = strToUtf8($text);
        if(isset($param['pseudo']) &&  $param['pseudo'] == 1){
            $title = trim($this->pseudoOriginal($title,$param['admin']['seller_id']),PHP_EOL);
            $tmpContent = $this->pseudoOriginal($tmpContent,$param['admin']['seller_id']);
        }
        if($tmpContent == strip_tags($tmpContent)){
            if(strpos($tmpContent,"\r\n")){
                $tmpContentArr = explode("\r\n",$tmpContent);
            }else{
                $tmpContentArr = explode(PHP_EOL,$tmpContent);
            }
            $tmpContent ='';
            foreach($tmpContentArr as $tmpVal) {
                if(!empty($tmpVal)){
                    $tmpContent .= "<p>{$tmpVal}</p>" . PHP_EOL;
                }
            }
        }
        // 图片本地化
        $tmpContent = $this->imgExtraction($tmpContent,$param['admin']['seller_id']);
        $description = $this->descExtraction($tmpContent);
        $data = [
            'module_id' => $param['module_id'],
            'category_id' => $param['category_id'],
            'main_content' => [],
            'sub_content' => [
                'title' => $title,
                'description' => $description,
                'publish_time' => date('Y-m-d H:i:s'),
                'content' => $tmpContent,
                'seo_title' => $title,
                'seo_keyword' => $keywords,
                'seo_description' => $description,
            ],
            'admin' => $param['admin'],
        ];
        $res = $this->saveContent($data);
        if($res['code']){
            return $res;
        }
        $subContent = $res['data'];
        $InnerChart = new InnerChart();
        $keywordList = $InnerChart->getAllInnerChart(['seller_id'=>$param['admin']['seller_id'],'website_id'=>$param['website_id'],'status'=>1],'weight desc','id,weight,keyword,url,new_page_open')['data'];
        $subContent->content = $this->autoLinks($subContent->content,$keywordList,$subContent);
        $subContent->save();
        return $res;
    }

    /**
     * 去除 addslashes 添加的反斜杠
     * @param $content
     * @return string
     */
    public function cleanContent($content): string
    {
        return stripslashes($content);
    }

    public function getHtmlXpath($content): \DOMXPath
    {
        $doc = new \DOMDocument('1.0','utf-8');
        if(!preg_match('/charset=utf-8/',$content)){
            $content = '<meta charset="utf-8">'.$content;
        }
        $doc->loadHTML($content);
        return new \DOMXPath($doc);
    }

    /**
     * 内链插入
     * @param $content
     * @param $keywordList
     * @return array|string|string[]|null
     * @throws \think\db\exception\DbException
     */
    public function autoLinks($content, $keywordList,$subContent = null)
    {
        $keyNum = config('system.keyword_num');
        $urlNum = config('system.keyword_url');
        $links = [];
        $content = $this->cleanContent($content);
        // 先移除已有的自动链接
        $content = preg_replace_callback('~<a data\-rel="autolink" .*?>(.*?)</a>~i', function ($match)use(&$old) {
            return $match[1];
        }, $content);
        if($subContent instanceof SubContent){
            $subContent -> innerChart() -> detach();
        }
        // 存储所有标签
        $content = preg_replace_callback('~(<a .*?>.*?</a>|<.*?>)~i', function ($match) use (&$links) {
            return '<' . array_push($links, $match[1]) . '>';
        }, $content);

        $cache = [];
        // 替换链接
        foreach ($keywordList as $item) {
            $i = 0;
            if($i > $keyNum){
                break;
            }
            $content = preg_replace_callback('/(' . $item['keyword'] . ')/i', function ($match) use ($item,&$i) {
                if(!empty($match)){
                    $i++;
                }
                $url = $item['url'];
                return '<a data-rel="autolink" href="' . $url . '"' . ($item['new_page_open'] == 2 ? ' target="_blank"' : '') . '>' . $match[0] . '</a>';
            }, $content, $urlNum);

            $content = preg_replace_callback('~(<a .*?>.*?</a>)~i', function ($match) use (&$links) {
                return '<' . array_push($links, $match[1]) . '>';
            }, $content);
            if($i != 0){
                if($subContent instanceof SubContent){
                    $subContent -> innerChart() -> attach($item->id,['num'=>$i]);
                }else{
                    $tmpCache = [
                        'inner_chart_id' => $item -> id,
                        'total' => $i,
                    ];
                    array_push($cache,$tmpCache);
                }
            }
        }
        $content = preg_replace_callback('/<(\d+)>/', function ($match) use (&$links) {
            return $links[$match[1] - 1];
        }, $content);
        if(!empty($cache)){
            Cache::set(md5(strip_tags($content)),$cache,300);
        }
        return $content;
    }

    public function autoLinkDeal()
    {

    }

    public function getModuleContent($table,$sellerId): array
    {
        $table = str_replace(env('database.prefix'),'',$table);
        // 判断用户自定义模型
        $module = new Module();
        $sellerModule = $module -> getAllCustomData(['seller_id'=>$sellerId])['data'];
        $sellerTable = array_column($sellerModule,'table');
        if(!empty($sellerTable) && in_array($table,$sellerTable)){
            $data = Db::name($table)->alias('cs')
                ->field('cs.*,sb.title as hc_main_title')
                ->leftJoin('sub_content sb','cs.sub_id = sb.id')
                ->where('sb.status',1)
                ->where('sb.is_del',1)
                ->order('cs.id desc')
                ->select()->toArray();
        }else{
            $ModuleFieldService = new ModuleFieldService();
            $field = $ModuleFieldService -> getModuleTableField($table)['data'];
            $field = array_column($field,'column_name');
            $query = Db::name($table)->where('seller_id',$sellerId);
            if(in_array('status',$field)){
                $query = $query -> where('status',1);
            }
            if(in_array('is_del',$field)){
                $query = $query -> where('is_del',1);
            }
            $res = $query -> select()->toArray();
            $data = [];
            if(!empty($res)){
                foreach($res as $val) {
                    $tmp = $val;
                    $tmp['hc_main_title'] = empty($val['title']) ? $val['name'] : $val['title'];
                    array_push($data,$tmp);
                }
            }
        }
        return dataReturn(0,'success',$data);
    }

    /**
     * 伪原创（百度翻译）
     * @throws ModelException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function pseudoOriginal($q,$sellerId): string
    {
        $trans = new TranslateService();
        $data = $this -> dealTransData($q);

        $str = '';
        foreach ($data as $val){
            $result = $trans -> baiduTranslate($val,'zh','en',$sellerId)['data'];
            $res = $trans -> baiduTranslate($result,'en','zh',$sellerId)['data'];
            $str .= $res . PHP_EOL;
        }
        return $str;
    }

    /**
     * 翻译长度处理
     * @param $data
     * @param int $len
     * @return array
     */
    public function dealTransData($data, int $len = 6000,&$dataArr=[]): array
    {
        $len_s = strlen($data);
        if($len_s > $len){
            $data1 = substr($data,0,$len);
            $index_zh = strrpos($data1,'。');
            $index_en = strrpos($data1,'.');
            if($index_zh > $index_en){
                $index = $index_zh + 3;
            }else{
                $index = $index_en + 1;
            }
            $tmpData1 = substr($data1,0,$index) . PHP_EOL;
            array_push($dataArr,$tmpData1);
            $tmpData = substr($data,$index,$len);
            $this->dealTransData($tmpData,$len,$dataArr);
        }else{
            array_push($dataArr,$data);
        }
        return $dataArr;
    }


}